#ifdef SYPX_MEMCHECK
#include "mmgr.h"
#endif

#include "Actor.h"
#include "WolfInstance.h"
#include "DogInstance.h"
#include "Level.h"

namespace SheepDefence
{
	DogInstance::DogInstance():targetSprite(0)
	{

	}

	DogInstance::~DogInstance()
	{
		delete staminaBar;
	}

	DogInstance::DogInstance(SypX::FileInputStream& fin, Dog* act, Level* lvl):targetSprite(0), original_x(0), original_y(0), target(NULL), next_target(NULL), actor(act), stamina(act->stam)
	{
		SypX::ErrorLogger::getLogger() << "Loading DogInstance...\n";

		fin >> x;
		fin >> y;
		fin >> angle;
		final_x = x;
		final_y = y;
		dest_x = x;
		dest_y = y;

		stateAge = 0;
		level = lvl;
		type = DOG;
		state = IDLE;
		stamState = NORMAL;
		pathState = OK;
		elapsed = 0;

		SypX::ErrorLogger::getLogger() << "Loaded: " << x << ", " << y << ", " << angle << "\n";

		sprite = new SypX::SpriteInstance();
		sprite->useSprite(act->sprite);

		sprite->setPosition(SypX::Vec3( static_cast<float>(x), static_cast<float>(y), 0.4f));
		sprite->setActiveAngle(angle);

		staminaBarMesh = new SypX::Mesh();
		staminaBarMesh->initAsQuad(7.0f, act->stam * 3, 0.99f);

		staminaBar = new SypX::MeshInstance();
		staminaBar->useMesh(staminaBarMesh);
		staminaBar->setPosition(SypX::Vec2(315.0f, act->stam * 1.5f + 5.0f));
	}

	DogInstance::DogInstance(Dog* act, Level* lvl, float x, float y, int angle): targetSprite(0), original_x(0), original_y(0), target(NULL), next_target(NULL), actor(act), stamina(act->stam)
	{
		SypX::ErrorLogger::getLogger() << "Loading DogInstance...\n";

		this->x = x;
		this->y = y;
		this->angle = angle;
		final_x = x;
		final_y = y;
		dest_x = x;
		dest_y = y;

		stateAge = 0;
		level = lvl;
		type = DOG;
		state = IDLE;
		stamState = NORMAL;
		pathState = OK;
		elapsed = 0;

		SypX::ErrorLogger::getLogger() << "Loaded: " << x << ", " << y << ", " << angle << "\n";

		sprite = new SypX::SpriteInstance();
		sprite->useSprite(act->sprite);

		sprite->setPosition(SypX::Vec3( static_cast<float>(x), static_cast<float>(y), 0.4f));
		sprite->setActiveAngle(angle);

		staminaBarMesh = new SypX::Mesh();
		staminaBarMesh->initAsQuad(7.0f, act->stam * 3, 0.99f);

		staminaBar = new SypX::MeshInstance();
		staminaBar->useMesh(staminaBarMesh);
		staminaBar->setPosition(SypX::Vec2(315.0f, act->stam * 1.5f + 5.0f));
	}

	void DogInstance::boundaryCheck(Actor* actor)
	{
		float new_x = dest_x > 320 ? 320 : dest_x < 0 ? 0 : dest_x;
		float new_y = dest_y > 480 ? 480 : dest_y < 0 ? 0 : dest_y;

		if (new_x != dest_x || new_y != dest_y)
		{
			dest_x = new_x;
			dest_y = new_y;

			if (state == POUNCING)
			{
				target = NULL;		// Release target

				if (next_target != NULL)
				{
					target = next_target;
					next_target = NULL;
					changeState(TRACKING);
					move(target->x, target->y);
				}
				else
				{
					changeState(RUNNING);
					move(x, y);
				}
			}
		}
	}

	void DogInstance::move(float x, float y, bool force)
	{
		bool updated = false;

		if (final_x != x || final_y != y)
		{
			final_x = x;
			final_y = y;
			updated = true;
		}

		// update pathing state
		if (state != POUNCING && state != BITING)
		{
			if (updated)
				exceptions = inObstacle(final_x, final_y, level->obstacles, actor->collision);

			if (force || level->timer_25 == 0 || getDist(dest_x - this->x, dest_y - this->y) < 50)
			{
				// direct path
				if (!collision(this->x, this->y, final_x, final_y, level->obstacles, actor->collision, exceptions))
				{
					dest_x = final_x;
					dest_y = final_y;

					if (exceptions.size() > 0)
						pathState = BANGING;
					else
						pathState = OK;
				}
				else
				{
					SypX::Vec2 dest = level->environment->getDest(this->x, this->y, final_x, final_y, level->obstacles, actor->collision, exceptions);

					dest_x = dest.x;
					dest_y = dest.y;

					if (dest_x == final_x && dest_y == final_y && exceptions.size() > 0)
						pathState = BANGING;
					else
						pathState = OK;
				}
			}
		}
	}

	void DogInstance::updateAttributes(SypX::Vec2 movement)
	{
		if (stamState == NORMAL || state == POUNCING)
			stamina -= sqrt(getDist(movement.x, movement.y));
	}

	void DogInstance::act(float time)
	{
		if (state == IDLE)
			stamina += time * actor->regen;

		stamina = stamina < -1 ? -1 : stamina;
		stamina = stamina > actor->stam ? actor->stam : stamina;

		if (stamState == TIRED && stamina > 0)
			stamState = NORMAL;

		if (stamState == NORMAL && stamina <= 0)
			stamState = TIRED;

		if (state == TRACKING)
		{
			if (getDist(target, this) < actor->pounce * actor->pounce)
			{
				// check for direct line of sight
				if (!collision(this->x, this->y, target->x, target->y, level->obstacles, actor->collision))
					changeState(POUNCING);
			}

			move(target->x, target->y);
		}

		if (state == POUNCING)
		{
			if (getDist(target, this) < 20)	// Target reached
			{
				// use biting texture
				changeState(BITING);
				target->changeState(BITTEN);
			}
			else
			{
				//dest_x = target->dest_x;
				//dest_y = target->dest_y;
				dest_x = target->x;
				dest_y = target->y;
			}
			return;
		}

		if (state == BITING)
		{
			target->hp -= actor->att * time;

			if (target->hp <= 0)
			{
				// use idle texture
				changeState(IDLE);
				level->numWolves--;
				SypX::ErrorLogger::getLogger()<<"WOLF DOWN: " << level->numWolves << "\n";
				target->changeState(DEAD);
				target = NULL;		// unload target

				if (next_target != NULL)
				{
					target = next_target;
					targetSprite = target->sprite;
					next_target = NULL;
					changeState(TRACKING);
					move(target->x, target->y);
				}
			}

			return;
		}

		if (state == RUNNING)
		{
			if (x == final_x && y == final_y)
				changeState(IDLE);
			else
				move(final_x, final_y);
		}

		if (state == STUCK)
		{
			dest_x = x;
			dest_y = y;
			final_x = x;
			final_y = y;
		}
	}

	bool DogInstance::collide(Instance* target)
	{
		if (target == this || (target->type == WOLF && state != RUNNING) || (target->type == SHEEP && target->state == BITTEN) || target->state == DEAD)
			return false;

		return true;
	}

	Actor* DogInstance::getActor()
	{
		return actor;
	}

	void DogInstance::drawStaminaBar()
	{
		float max = actor->stam;
		float effStam = stamina < 0.4f ? 0.4f : stamina;

		staminaBarMesh->resizeQuad(7.0f, effStam * 1.5f);
		staminaBar->setPosition(SypX::Vec2( staminaBar->getPositionRef().x ,effStam * 0.75f + 5.0f));

		float green = (effStam / max ) * 1.25f - 0.25f;
		green = green > 1 ? 1 : (green < 0 ? 0 : green);

		float red = 1 - green;

		float patch = red * green;
		red += patch;
		green += patch;

		SypX::Engine::getSingleton()->getRenderer()->setActiveColor(SypX::Vec4(red, green, 0.0f, 0.7f));
		SypX::Engine::getSingleton()->getRenderer()->drawMesh(staminaBar);
	}
}
